package puffer.starter.generate._0_0_1_puffer_admin;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Generator {

    public static void main(String[] args) {
        startGenerator();
    }

    //模板位置
    private static String template = "_0_0_1_puffer_admin";
    private static String basePackage = "puffer.admin";
    private static String moduleName = "system";
    //顶层包
    private static String driverName = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://127.0.0.1:3306/puffer?"
            + "serverTimezone=Asia/Shanghai&characterEncoding=UTF8&"
            + "zeroDateTimeBehavior=convertToNull&useUnicode=true&"
            + "useSSL=false&useTimezone=false";
    private static String userName = "root";
    private static String password = "1234qwer";

    //生成指定表
    private static List<String> createTables = new ArrayList<>();
    //排除指定表
    private static List<String> excludeTables = new ArrayList<>();
    //删除表前缀
    private static List<String> removeTablePrefix = new ArrayList<>();
    //删除字段前缀
    private static List<String> removeFilePrefix = new ArrayList<>();


    private static String createPath = System.getProperty("user.dir") + "/generator/";
    private final static String controllerPath = createPath + basePackage + "/module/" + moduleName + "/controller";
    private final static String servicePath = createPath + basePackage + "/module/" + moduleName + "/service";
    private final static String serviceImplPath = createPath + basePackage + "/module/" + moduleName + "/service/impl";
    private final static String entityPath = createPath + basePackage + "/mybatis/table";
    private final static String mapperPath = createPath + basePackage + "/mybatis/mapper";
    private final static String mapperXmlPath = createPath + basePackage + "/mybatis/mapper/xml";
    private final static String daoPath = createPath + basePackage + "/mybatis/service";
    private final static String daoImplPath = createPath + basePackage + "/mybatis/service/impl";


    private static AutoGenerator generator = null;


    private synchronized static void startGenerator() {
        System.out.println("==========================文件生成开始==========================");
        //清空旧文件
        delete(new File(createPath));
        //生成文件
        generator = new AutoGenerator();
        //全局配置
        setGlobalConfig();
        //数据源配置
        setDataSource();
        //策略配置
        setStrategy();
        //包配置
        setPackage();
        //注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
        setCfg();
        //模板配置
        setTemplate();
        //执行
        generator.execute();
        //删掉垃圾文件
        delete(new File(createPath + "/z_z_z_z"));
        delete(new File(mapperXmlPath));
        System.out.println("==========================文件生成完毕==========================");
        //        delete(new File(createPath + "/resources"));
        //        delete(new File(mapperPath));
        //        delete(new File(mapperXmlPath));
        //        delete(new File(daoPath));
    }

    //全局配置
    private static void setGlobalConfig() {
        generator.setGlobalConfig(
                new GlobalConfig()
                        .setActiveRecord(true)
                        .setOutputDir(createPath)
                        .setOpen(false)
                        .setAuthor("王永吉")
                        .setFileOverride(false)
                        .setEnableCache(false)
                        .setBaseResultMap(false)
                        .setBaseColumnList(false)
                        .setKotlin(false)
                //                  .setOpen(true)
                //                 .setMapperName("%sDao")
                //                .setEntityName("%s")
                //                .setXmlName("%sMapper")
                //                .setServiceName("I%sService")
                //                .setServiceImplName("%sServiceImpl")
                //                .setControllerName("%sRestController");
        );
    }

    //数据源配置
    private static void setDataSource() {
        generator.setDataSource(
                new DataSourceConfig()
                        .setDbType(DbType.MYSQL)
                        .setDriverName(driverName)
                        .setUrl(url)
                        .setUsername(userName)
                        .setPassword(password)
                        // 自定义数据库表字段类型转换【可选】
                        .setTypeConvert(new MySqlTypeConvert() {
                            @Override
                            public DbColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                                if (fieldType.toLowerCase().contains("bigint")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("varchar")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("char")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("longtext")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("tinyint")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("json")) {
                                    return DbColumnType.STRING;
                                }
                                if (fieldType.toLowerCase().contains("datetime")) {
                                    return DbColumnType.LOCAL_DATE_TIME;
                                }
                                if (fieldType.toLowerCase().contains("date")) {
                                    return DbColumnType.LOCAL_DATE;
                                }
                                if (fieldType.toLowerCase().contains("time")) {
                                    return DbColumnType.LOCAL_TIME;
                                }
                                return (DbColumnType) super.processTypeConvert(globalConfig, fieldType);
                            }
                        }));
    }

    //策略配置
    private static void setStrategy() {
        StrategyConfig strategyConfig = new StrategyConfig();
        //设置实体列常量
        strategyConfig.setEntityColumnConstant(true);
        //        设置表格填充列表
        strategyConfig.setTableFillList(getTableFills());
        //        设置实体表字段注释启用
        strategyConfig.setEntityTableFieldAnnotationEnable(true);
        //        设置休息控制器样式
        strategyConfig.setRestControllerStyle(false);
        //        Lombok
        strategyConfig.setEntityLombokModel(true);
        //        设置命名规则
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        //        设置列命名，驼峰下划线
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);

        if (createTables != null && createTables.size() > 0) {
            strategyConfig.setInclude((String[]) createTables.toArray());
        }

        if (excludeTables != null && excludeTables.size() > 0) {
            strategyConfig.setExclude((String[]) excludeTables.toArray());
        }
        if (removeTablePrefix != null && removeTablePrefix.size() > 0) {
            strategyConfig.setTablePrefix((String[]) removeTablePrefix.toArray());
        }
        if (removeFilePrefix != null && removeFilePrefix.size() > 0) {
            strategyConfig.setFieldPrefix((String[]) removeFilePrefix.toArray());
        }

        //.setSuperMapperClass("com.big.mybatis.base.BaseMapper")
        // strategy.setCapitalMode(true)// 全局大写命名 ORACLE 注意
        //strategy.setSuperControllerClass("com.sample.model.common.BaseController") //指定 顶层 Controller
        //strategy.setSuperEntityClass("com.sample.model.common.BaseEntity") //指定 顶层 实体类
        //strategy.setSuperEntityColumns("id")  //抽出公用 字段
        //strategy.setControllerMappingHyphenStyle(true)    //驼峰 变为  "-"
        generator.setStrategy(strategyConfig);
    }

    //包配置
    private static void setPackage() {
        generator.setPackageInfo(
                new PackageConfig()
                        .setParent("z_z_z_z")
                        .setMapper("z_z_z_z")
                        .setEntity("z_z_z_z")
        );
    }

    //注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
    private static void setCfg() {
        FileOutConfig cMapper = new FileOutConfig(template + "/mapper.java.ftl") {
            // 自定义输出文件目录
            @Override
            public String outputFile(TableInfo tableInfo) {
                return mapperPath + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cMapperXml = new FileOutConfig(template + "/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return mapperXmlPath + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        };
        FileOutConfig cEntity = new FileOutConfig(template + "/entity.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return entityPath + "/" + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cController = new FileOutConfig(template + "/controller.java.ftl") {
            // 自定义输出文件目录
            @Override
            public String outputFile(TableInfo tableInfo) {
                return controllerPath + "/" + tableInfo.getEntityName() + "Controller" + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cService = new FileOutConfig(template + "/service.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return servicePath + "/" + tableInfo.getEntityName() + "Service" + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cServiceImpl = new FileOutConfig(template + "/serviceImpl.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return serviceImplPath + "/" + tableInfo.getEntityName() + "ServiceImpl" + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cDao = new FileOutConfig(template + "/iservice.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return daoPath + "/I" + tableInfo.getEntityName() + "Service" + StringPool.DOT_JAVA;
            }
        };
        FileOutConfig cDaoImpl = new FileOutConfig(template + "/iserviceimpl.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return daoImplPath + "/I" + tableInfo.getEntityName() + "ServiceImpl" + StringPool.DOT_JAVA;
            }
        };


        List<FileOutConfig> fileOutConfigs = new ArrayList<>();
        fileOutConfigs.add(cMapper);
        fileOutConfigs.add(cMapperXml);
        fileOutConfigs.add(cEntity);
        fileOutConfigs.add(cController);
        fileOutConfigs.add(cService);
        fileOutConfigs.add(cServiceImpl);
        fileOutConfigs.add(cDao);
        fileOutConfigs.add(cDaoImpl);
        generator.setCfg(
                new InjectionConfig() {
                    @Override
                    public void initMap() {
                        Map<String, Object> map = new HashMap<>();
                        map.put("basePackage", basePackage);
                        map.put("moduleName", moduleName);
                        map.put("date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")));
                        this.setMap(map);
                    }
                }.setFileOutConfigList(fileOutConfigs)
        );
    }

    //模板配置
    private static void setTemplate() {
        generator.setTemplateEngine(new FreemarkerTemplateEngine());
        generator.setTemplate(
                new TemplateConfig()
                        .setController(template + "/controller.java")
                        .setService(template + "/service.java")
                        .setServiceImpl(template + "/serviceImpl.java")
                        .setXml(template + "/mapper.xml")
                        .setMapper(template + "/mapper.java")
                        .setEntity(template + "/entity.java")
        );
    }


    private static void yamlToJson(String s) {
        //        Map<String, Object> loaded = null;
        //        try {
        //            FileInputStream fis = new FileInputStream(s + propertyPath);
        //            Yaml yaml = new Yaml();
        //            loaded = yaml.load(fis);
        //        } catch (FileNotFoundException ex) {
        //            ex.printStackTrace();
        //        }
        //        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(loaded);
        //        JSONObject spring = (JSONObject) jsonObject.get("spring");
        //        JSONObject datasource = (JSONObject) spring.get("datasource");
        //        return datasource;
    }

    //去除表前缀
    //    private static String[] removeTablePrefix() {
    //        StringBuilder tablePrefix = new StringBuilder();
    //        tablePrefix.append("a_z_").append(",");
    //        tablePrefix.append("0_").append(",");
    //        tablePrefix.append("_").append(",");
    //        for (int i = 0; i < 26; i++) {
    //            tablePrefix.append((char) ('a' + i)).append("_").append(",");
    //        }
    //        return (String[])removeTablePrefix.toArray();
    //        tablePrefix.toString().split(",");
    //        return null;
    //    }

    //去除字段前缀
    //    private static String[] removeFilePrefix() {
    //        return "".split(",");
    //    }

    /**
     * 设置填充策略
     */
    protected static List<TableFill> getTableFills() {
        // 自定义需要填充的字段
        List<TableFill> tableFillList = new ArrayList<>();
        tableFillList.add(new TableFill("d_ci", FieldFill.INSERT));
        tableFillList.add(new TableFill("d_ui", FieldFill.INSERT_UPDATE));
        tableFillList.add(new TableFill("d_cn", FieldFill.INSERT));
        tableFillList.add(new TableFill("d_un", FieldFill.INSERT_UPDATE));
        tableFillList.add(new TableFill("d_ct", FieldFill.INSERT));
        tableFillList.add(new TableFill("d_ut", FieldFill.INSERT_UPDATE));
        return tableFillList;
    }

    /**
     * 递归删除文件
     */
    public static void delete(File file) {
        if (!file.exists()) return;
        if (!file.isFile() && file.list() != null) {
            File[] files = file.listFiles();
            assert files != null;
            for (File a : files) {
                delete(a);
            }
        }
        file.delete();
    }

    /**
     * 调用模板生成器（不需要的添NULL）
     *
     * @param userName          数据库账号
     * @param password          数据库密码
     * @param driverName        驱动类路径
     * @param url               URL
     * @param template          模板位置
     * @param basePackage       顶层包名
     * @param moduleName        模块名
     * @param createPath        代码生成位置
     * @param createTables      生成表
     * @param excludeTables     排除表
     * @param removeTablePrefix 删除表前缀
     * @param removeFilePrefix  删除字段前缀
     */
    public static void generator(String userName, String password,
                                 String driverName, String url,
                                 String template, String basePackage, String moduleName, String createPath,
                                 List<String> createTables, List<String> excludeTables,
                                 List<String> removeTablePrefix, List<String> removeFilePrefix
    ) {
        Generator.url = url;
        Generator.driverName = driverName;
        Generator.userName = userName;
        Generator.password = password;
        Generator.createTables = createTables;
        Generator.excludeTables = excludeTables;
        Generator.template = template;
        Generator.basePackage = basePackage;
        Generator.createPath = createPath;
        Generator.removeTablePrefix = removeTablePrefix;
        Generator.removeFilePrefix = removeFilePrefix;
        Generator.moduleName = moduleName;
        startGenerator();
    }

}



